package com.example.springhibernate.exception;

import com.example.springhibernate.dto.ParamException;
import com.example.springhibernate.dto.ResponseDto;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import static com.example.springhibernate.constant.ExceptionConstatnt.PARAM_IS_NULL_ERROR;
import static com.example.springhibernate.constant.ExceptionConstatnt.PARAM_VALID_ERROR;

/**
 * ExceptionAdvice
 *
 * @author zhouxianfeng
 * @date 2021-4-14
 */
@ControllerAdvice
@Order(0)
public class ExceptionAdvice {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);


    @Resource
    private MessageSource messageSource;

    @ResponseBody
    @ResponseStatus(
            code = HttpStatus.BAD_REQUEST
    )
    @ExceptionHandler({Exception.class})
    protected Object handleBusinessException(Exception exception, HttpServletRequest request, HttpServletResponse response) {
        logger.error("got a BusinessException", exception);

        return exception;
    }


    @ResponseBody
    @ResponseStatus(
            code = HttpStatus.BAD_REQUEST
    )
    @ExceptionHandler({HttpMessageNotReadableException.class})
    protected ResponseDto handleBusinessException(HttpMessageNotReadableException exception, HttpServletRequest request,
                                                  HttpServletResponse response) {
        logger.error(PARAM_IS_NULL_ERROR, exception);
        String code = PARAM_IS_NULL_ERROR;
        Locale locale = request.getLocale();
        String message = messageSource.getMessage(code, new Object[]{}, locale);
        return new ResponseDto(code, null, message);
    }


    @ResponseBody
    @ResponseStatus(
            code = HttpStatus.BAD_REQUEST
    )
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseDto resolveConstraintViolationException(ConstraintViolationException ex) {
        logger.error(PARAM_VALID_ERROR, ex);
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        List<ParamException> exceptions= Lists.newArrayList();
        for (ConstraintViolation constraintViolation : constraintViolations) {
            exceptions.add(new ParamException(constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage()));
        }
        String code = PARAM_VALID_ERROR;
        Locale locale = LocaleContextHolder.getLocale();
        String message = messageSource.getMessage(code, new Object[]{}, locale);
        return new ResponseDto(code, exceptions, message);

    }

    /**
     * 400,用来处理方法参数异常
     *
     * @param ex
     * @return
     */
    @ResponseBody
    @ResponseStatus(
            code = HttpStatus.BAD_REQUEST
    )
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseDto resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        logger.error(PARAM_VALID_ERROR, ex);
        List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
        List<ParamException> exceptions = Lists.newArrayList();
        for (ObjectError objectError : objectErrors) {
            String code = null;
            Object[] arguments = objectError.getArguments();
            if (arguments.length > 0 && arguments[0] instanceof DefaultMessageSourceResolvable) {
                DefaultMessageSourceResolvable resolvable = (DefaultMessageSourceResolvable) arguments[0];
                code = resolvable.getCode();
            }
            String message = objectError.getDefaultMessage();
            exceptions.add(new ParamException(code, message));
        }
        String code = PARAM_VALID_ERROR;
        Locale locale = LocaleContextHolder.getLocale();
        String message = messageSource.getMessage(code, new Object[]{}, locale);

        return new ResponseDto(code, exceptions, message);

    }



}
